package com.shanlitech.bluetooth.map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.util.Log;

import com.shanlitech.lbs.geometry.Point2D;

import java.io.InputStream;
import java.util.Locale;

public class MapMarker implements Draggable {
    public static final String TAG = "Map2D";

    public static final int ANCHOR_LEFT_TOP = 1;
    public static final int ANCHOR_RIGHT_BOTTOM = 2;
    public static final int ANCHOR_CENTER = 3;
    public static final int ANCHOR_TOP_MIDDLE = 4;
    public static final int ANCHOR_BOTTOM_MIDDLE = 5;

    public static final int TEXT_NONE = 0;
    public static final int TEXT_NAME = 1;
    public static final int TEXT_COORDINATE = 2;
    public static final int TEXT_NAME_COORDINATE = 3;

    public static class Builder {
        private final String name;
        private final Context context;
        private Bitmap bitmap;
        private int anchor = ANCHOR_LEFT_TOP;
        private final Point2D coordinate = new Point2D();
        private final Size drawSize = new Size();
        private boolean draggable = true;
        private int textMode = TEXT_NONE;
        private float strokeWidth = 2.f;
        private float textSize = 20.f;
        private int textColor = Color.BLACK;

        public Builder(Context context,String name) {
            this.context = context;
            this.name = name;
        }

        public Builder loadImage(String img) {
            bitmap = ImageLoader.load(context,img);
            return this;
        }

        public Builder setDraggable(boolean b) {
            draggable = b;
            return this;
        }

        public Builder setDrawSize(int width,int height) {
            drawSize.width = width;
            drawSize.height = height;
            return this;
        }

        public Builder setAnchor(int anchor) {
            this.anchor = anchor;
            return this;
        }

        public Builder setCoordinate(double x,double y) {
            coordinate.x = x;
            coordinate.y = y;
            return this;
        }

        public Builder setCoordinate(Point2D point) {
            coordinate.x = point.x;
            coordinate.y = point.y;
            return this;
        }

        public Builder setStrokeWidth(float w) {
            strokeWidth = w;
            return this;
        }

        public Builder setTextMode(int mode) {
            textMode = mode;
            return this;
        }

        public Builder setTextSize(float size) {
            textSize = size;
            return this;
        }

        public Builder setTextColor(int color) {
            textColor = color;
            return this;
        }

        public MapMarker build() {
            if( bitmap != null ) {
                final MapMarker marker = new MapMarker(name);
                if( drawSize.width == 0 || drawSize.height == 0 ) {
                    drawSize.width = bitmap.getWidth();
                    drawSize.height = bitmap.getHeight();
                }
                marker.setImage(bitmap,anchor,drawSize);
                marker.mCoordinate.set(coordinate.x,coordinate.y);
                marker.setDraggable(draggable);
                marker.setTextMode(textMode);
                marker.setStrokeWidth(strokeWidth);
                marker.setTextSize(textSize);
                marker.setTextColor(textColor);
                return marker;
            }
            return null;
        }

        private Point getAnchor() {
            final Point point = new Point();
            switch( anchor ) {
                case ANCHOR_LEFT_TOP:
                    point.x = 0; point.y = 0;
                    break;
                case ANCHOR_RIGHT_BOTTOM:
                    point.x = bitmap.getWidth();
                    point.y = bitmap.getHeight();
                    break;
                case ANCHOR_CENTER:
                    point.x = bitmap.getWidth() / 2;
                    point.y = bitmap.getHeight() / 2;
                    break;
                case ANCHOR_TOP_MIDDLE:
                    point.x = bitmap.getWidth() / 2;
                    point.y = 0;
                    break;
                case ANCHOR_BOTTOM_MIDDLE:
                    point.x = bitmap.getWidth() / 2;
                    point.y = bitmap.getHeight();
                    break;
                default:
                    break;
            }
            return point;
        }
    }

    protected final String      mName;
    protected final Paint mPaint = new Paint();
    protected final Rect  mImageRect = new Rect();
    protected final Size  mImageSize = new Size();
    protected final Point mAnchor = new Point();
    protected final Size  mDrawSize = new Size();
    protected final Point2D mCoordinate = new Point2D();
    protected final Rect  mDrawRect = new Rect();
    protected final Size mMaxDrawSize = new Size();

    protected Bitmap      mImage;
    protected float       mDrawScale = 1.0f;
    protected boolean     mDraggable = true;
    protected int         mTextMode = TEXT_NONE;
    protected int         mAnchorMode = ANCHOR_CENTER;

    protected MapMarker(String name) {
        this.mName = name;
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(2);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(20);
    }

    public String getName() {
        return mName;
    }

    public void setImage(Bitmap bitmap,int anchorMode,Size drawSize) {
        mImage = bitmap;
        mAnchorMode = anchorMode;
        if( drawSize != null && drawSize.width > 0 && drawSize.height > 0 ) {
            mMaxDrawSize.set(drawSize.width, drawSize.height);
        } else {
            mMaxDrawSize.set(bitmap.getWidth(),bitmap.getHeight());
        }
        mImageRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
        mImageSize.set(bitmap.getWidth(), bitmap.getHeight());
        updateAnchor();
        updateDrawSize();
    }

    public boolean isDraggable() {
        return mDraggable;
    }

    public void setDraggable(boolean b) {
        mDraggable = b;
    }

    @Override
    public Rect getObjectRect(WindowMapCoordinator coordinator) {
        if( mDraggable ) {
            updateDrawRect(coordinator);
        }
        return mDrawRect;
    }

    @Override
    public void move(float pixelX, float pixelY, WindowMapCoordinator coordinator) {
        if( mDraggable ) {
            updateDrawRect(coordinator);
            mCoordinate.x += coordinator.pixelsToMeter(pixelX);
            mCoordinate.y += coordinator.pixelsToMeter(-pixelY); // 坐标系Y轴相反
            updateDrawRect(coordinator);
        }
    }


    public void setTextMode(int mode) {
        mTextMode = mode;
    }

    public void setStrokeWidth(float w) {
        mPaint.setStrokeWidth(w);
    }

    public void setTextSize(float size) {
        mPaint.setTextSize(size);
    }

    public void setTextColor(int color) {
        mPaint.setColor(color);
    }

    public Bitmap getImage() {
        return mImage;
    }

    public Rect getImageRect() {
        return mImageRect;
    }

    public Point getAnchor() {
        return mAnchor;
    }

    public Size getImageSize() {
        return mImageSize;
    }

    public Size getDrawSize() {
        return mDrawSize;
    }

    public Point2D getCoordinate() {
        return mCoordinate;
    }

    public void setCoordinate(Point2D point) {
        mCoordinate.copy(point);
    }

    public void setCoordinate(double x,double y) {
        mCoordinate.x = x;
        mCoordinate.y = y;
    }

    public Rect getDrawRect() {
        return mDrawRect;
    }

    public void draw(Canvas canvas, Paint paint,WindowMapCoordinator coordinator,VisibleChecker visibleChecker) {
        draw(canvas,paint,coordinator.mapToWindowX(mCoordinate.x,mCoordinate.y),coordinator.mapToWindowY(mCoordinate.x,mCoordinate.y),visibleChecker);
    }

    public void draw(Canvas canvas, Paint paint,float x,float y,VisibleChecker visibleChecker) {
        updateDrawRect(x,y);
        if( visibleChecker.visibleRect(mDrawRect) ) {
            canvas.drawBitmap(mImage, mImageRect, mDrawRect, paint);

            String text = null;
            if( mTextMode == TEXT_COORDINATE ) {
                text = String.format(Locale.getDefault(), "%.1f,%.1f", mCoordinate.x, mCoordinate.y);
            } else if( mTextMode == TEXT_NAME ) {
                text = mName;
            } else if( mTextMode == TEXT_NAME_COORDINATE ) {
                text = String.format(Locale.getDefault(), "%s(%.1f,%.1f)",mName, mCoordinate.x, mCoordinate.y);
            }

            if( text != null ) {
                canvas.drawText(text, (mDrawRect.left + mDrawRect.right) / 2.f, mDrawRect.bottom + mPaint.getTextSize(), mPaint);
            }
        }
    }

    protected void updateDrawSize() {
        final float scaleX = (float) mMaxDrawSize.width / (float)mImageSize.width ;
        final float scaleY =  (float) mMaxDrawSize.height / (float)mImageSize.height;
        mDrawScale = Math.abs(scaleX - 1.0f) < Math.abs(scaleY - 1.0f) ? scaleX : scaleY;
        mDrawSize.set((int)(mImageSize.width * mDrawScale),(int)(mImageSize.height * mDrawScale));
    }

    protected void updateDrawRect(WindowMapCoordinator coordinator) {
        updateDrawRect(coordinator.mapToWindowX(mCoordinate.x,mCoordinate.y),coordinator.mapToWindowY(mCoordinate.x,mCoordinate.y));
    }

    protected void updateDrawRect(float x,float y) {
        mDrawRect.left = Math.round(x - mAnchor.x * mDrawScale);
        mDrawRect.top = Math.round(y - mAnchor.y * mDrawScale);
        mDrawRect.right = mDrawRect.left + mDrawSize.width;
        mDrawRect.bottom = mDrawRect.top + mDrawSize.height;
    }

    private void updateAnchor() {
        switch( mAnchorMode ) {
            case ANCHOR_LEFT_TOP:
                mAnchor.x = 0; mAnchor.y = 0;
                break;
            case ANCHOR_RIGHT_BOTTOM:
                mAnchor.x = mImage.getWidth();
                mAnchor.y = mImage.getHeight();
                break;
            case ANCHOR_CENTER:
                mAnchor.x = mImage.getWidth() / 2;
                mAnchor.y = mImage.getHeight() / 2;
                break;
            case ANCHOR_TOP_MIDDLE:
                mAnchor.x = mImage.getWidth() / 2;
                mAnchor.y = 0;
                break;
            case ANCHOR_BOTTOM_MIDDLE:
                mAnchor.x = mImage.getWidth() / 2;
                mAnchor.y = mImage.getHeight();
                break;
            default:
                break;
        }
    }
}
